
// ****************************** //
// HELPER FUNCTIONS / DEFINITIONS //
// ****************************** //

// from https://github.com/MrFizzyBubbs/fizz-sccs/blob/main/kolmafia/scripts/fizz-sccs-lib.ash

void assert(boolean condition, string message) {
  if (!condition) abort(message);
}

boolean have(item it, int amount) {
  return available_amount(it) >= amount;
}

boolean have(item it) {
  return have(it, 1);
}

boolean have(effect ef) {
  return have_effect(ef).to_boolean();
}


void acquire(item it) {
  if (!have(it)) retrieve_item(1, it);
  assert(have(it), "Failed to acquire item");
}

void pull(item it, int price) {
  if (storage_amount(it) < 1) buy_using_storage(1, it, price);
  assert(take_storage(1, it), "Failed to pull item");
}

void pull(item it) {
  pull(it, 0);
}

void tryUse(item it) {
  if (available_amount(it) > 0) use(1, it);
}

void ensureMp(int mp) {
  while (my_mp() < mp && my_meat() >= 90) { // don't buy if we don't have enough meat
    acquire($item[Doc Galaktik\'s Invigorating Tonic]);
    use(1, $item[Doc Galaktik\'s Invigorating Tonic]);
  }
}

void ensureHp(float percent) {
  if (my_hp() < percent * my_maxhp()) {
    ensureMp(mp_cost($skill[Cannelloni Cocoon]));
    use_skill(1, $skill[Cannelloni Cocoon]);
  }
}

void acquire(effect ef) {
  if (ef != $effect[none]) {
    assert(have(ef) || !ef.default.starts_with("cargo"), "Can't obtain {ef}?");
    if (!have(ef)) cli_execute(ef.default);
    assert(have(ef), "Failed to acquire effect");
  }
}

// from https://github.com/Malurth/Auto-2-day-HCCS/blob/master/scripts/AutoHCCS.ash
int advCost(int whichtest) {
  buffer page = visit_url("council.php");
  string teststr = "name=option value="+ whichtest +">";
  if (contains_text(page, teststr)) {
    int chars = 140; //chars to look ahead
    string pagestr = substring(page, page.index_of(teststr)+length(teststr), page.index_of(teststr)+length(teststr)+chars);
    string advstr = substring(pagestr, pagestr.index_of("(")+1, pagestr.index_of("(")+3);
    advstr = replace_string(advstr, " ", ""); //removes whitespace, if the test is < 10 adv
    return to_int(advstr);
  } else {
    print("[ERROR] Didn't find specified test on the council page. Already done?");
    return 99999;
  }
}



boolean doTest(int which) {
  if (my_adventures() >= advCost(which)) {
    print("[!] Undertaking community service task at a cost of " + advCost(which) + " adventures", "teal");
    if (true) {
    // if(to_lower_case(user_prompt("Are you sure you want to continue? Y/N")) == "y") {
      visit_url("choice.php?whichchoice=1089&option="+which+"&pwd="+my_hash());
      return true;
    } else {
      abort("User aborted script");
      return false;
    }
  } else {
    abort("Failed to generate enough adventures to complete test " + which);
    return false;
  }
}

boolean haveModelTrainSet() {
  return get_workshed() == $item[model train set];
}

void modelTrainSet() {
  // tested to work
  if (!haveModelTrainSet()) {
    abort("You don't have the model train set!");
    return;
  }
  /* train set part reference
  1: meat
  2: mp regen
  3: all stats
  4: hot resist, cold damage
  5: stench resist, spooky damage
  6: wood, joiners, or stats (orc chasm bridge stuff); never good for CS
  7: candy
  8: double next stop
  9: cold resist, stench damage
  11: spooky resist, sleaze damage
  12: sleaze resist, hot damage
  13: monster level
  14: mox stats
  15: basic booze
  16: mys stats
  17: mus stats
  18: food drop buff
  19: copy last food drop
  20: ore
  
  coal/brain silo/viewing platform/water bridge/fizzy tower/frozen tower/meat/grain silo (for booze)  1, 
  (in this order, so you will start your leveling cycle on the coal station)
  8, 16, 3, 13, 2, 4, 1, 15
  */
  if (visit_url("campground.php?action=workshed",false,true).contains_text('value="Save Train Set Configuration"')) {
    //meat,double,main,all stats,alt1,alt2,ML,hot resist
    visit_url(`choice.php?pwd&whichchoice=1485&option=1&slot[0]=8&slot[1]=16&slot[2]=3&slot[3]=13&slot[4]=2&slot[5]=4&slot[6]=1&slot[7]=15`,true,true);
  }
  // let mafia know we're not stuck in the choice
  visit_url("main.php");
}

// ensure we are safe before fighting
void ensureSafeAdv() {
  print("Ensuring safe adventuring...", "teal");
  // restore mp with soul food whenever we can
  if (my_mp() < my_maxmp()) {
    while (my_soulsauce() >= soulsauce_cost($skill[soul food])) {
      use_skill(1, $skill[soul food]);
    }
  }
  // check for beaten up
  if (have($effect[Beaten Up])) {
    cli_execute("skill tongue of the walrus");
  }
  ensureHp(1.0);
  ensureHp(1.0);
  ensureHp(1.0);
  ensureHp(1.0); // 100% health so we don't get destroyed

  // sometimes, the mood will make us cast spells that cause mp to drop below this number.
  // one time the script couldn't run because we didn't have enough mp
  ensureMp(120); // higher so that we don't run out of mp
}

boolean drinkPerfectDrink() {
  // make perfect drink
  // make ice cube, need 5 mp
  // we may not have enough at buff space here, but not sure if this is a big deal
  use_skill(1, $skill[Perfect Freeze]);

  if (have($item[bottle of vodka])) {
    craft("cocktail", 1, $item[bottle of vodka], $item[perfect ice cube]);
    ensureMp(50);
    cli_execute("shrug magical mojo");
    use_skill(1, $skill[Ode to Booze]);
    drink(1, $item[Perfect cosmopolitan]);
    return true;
  } 
  else if (have($item[bottle of whiskey])) {
    craft("cocktail", 1, $item[bottle of whiskey], $item[perfect ice cube]);
    ensureMp(50);
    cli_execute("shrug magical mojo");
    use_skill(1, $skill[Ode to Booze]);
    drink(1, $item[Perfect old-fashioned]);
    return true;
  } 
  else if (have($item[bottle of rum])) {
    craft("cocktail", 1, $item[bottle of rum], $item[perfect ice cube]);
    ensureMp(50);
    cli_execute("shrug magical mojo");
    use_skill(1, $skill[Ode to Booze]);
    drink(1, $item[Perfect dark and stormy]);
    return true;
  } 
  else if (have($item[bottle of tequila])) {
    craft("cocktail", 1, $item[bottle of tequila], $item[perfect ice cube]);
    ensureMp(50);
    cli_execute("shrug magical mojo");
    use_skill(1, $skill[Ode to Booze]);
    drink(1, $item[Perfect paloma]);
    return true;
  } 
  else if (have($item[bottle of gin])) {
    craft("cocktail", 1, $item[bottle of gin], $item[perfect ice cube]);
    ensureMp(50);
    cli_execute("shrug magical mojo");
    use_skill(1, $skill[Ode to Booze]);
    drink(1, $item[Perfect negroni]);
    return true;
  } 
  else if (have($item[boxed wine])) {
    craft("cocktail", 1, $item[boxed wine], $item[perfect ice cube]);
    ensureMp(50);
    cli_execute("shrug magical mojo");
    use_skill(1, $skill[Ode to Booze]);
    drink(1, $item[Perfect mimosa]);
    return true;
  }
  return false;
}

boolean makeReagents() {
  // only attempt to make if we have a range
  if (get_property("hasRange").to_boolean()) {
    // get potions, we only need these 3
    // should check for existence of these items first
    if ($item[cherry].available_amount() > 0 && $item[scrumptious reagent].available_amount() > 0) {
        create(1, $item[oil of expertise]);
    }

    if ($item[grapefruit].available_amount() > 0 && $item[scrumptious reagent].available_amount() > 0) {
      create(1, $item[ointment of the occult]);
    }

    if ($item[lemon].available_amount() > 0 && $item[scrumptious reagent].available_amount() > 0) { //you've run out of reagants by now without way of sauce
      create(1, $item[philter of phorce]);
    }
    
    // use 2 ointments of the occult; we have 3, and we only need 1 for the test
    cli_execute("use 2 ointment of the occult");
    return true;
  }
  return false;
}

boolean rufusQuest(boolean fightBoss) {
  // string [int] choices;
  // string target;

  // check if quest started
  if (get_property("questRufus") == "unstarted") {
    set_property("choiceAdventure1497", "1"); // fight shadow boss
    cli_execute("use closed-circuit pay phone");
    // run_choice(1); // fight the boss, because it's too much of a hassle to write a script for the artifact quest
    // run_choice(2); // accept the artifact quest, get 11 turns of free fights
  }

  // run combat 11 times. it's all free fights anyway
  cli_execute("ccs cs_powerlevel");
  for i from 1 to 11 {
    adv1($location[Shadow Rift (The Nearby Plains)], -1, '');
    ensureSafeAdv();
  }

  // fight the boss
  // there are only 2 problematic bosses
  // scythe does 90% hp dmg so we just want to kill it quickly
  // orrery reflects all spells so we equip saber and just autoattack
  // spire can't get staggered so we skip curse of weaksauce
  if (fightBoss) {

    cli_execute("maximize hp, dr, mys, equip saber, equip unbreakable umbrella");
    cli_execute("familiar mosquito");
    cli_execute("ccs cs_shadowboss");
    /*
    [ default ]
    while monstername "shadow orrery"
        attack with weapon
    endwhile
    while monstername "shadow scythe"
        skill saucegeyser
    endwhile
    while monstername "shadow spire"
        skill saucegeyser
    endwhile
    skill curse of weaksauce
    skill stuffed mortar shell
    skill saucegeyser
    */
    
    
    // fight the boss
    ensureSafeAdv();
    ensureMp(300);
    adv1($location[Shadow Rift], -1, '');

    // check if we won
    if (to_boolean(get_property("_lastCombatWon"))) {
      // we won, we can get the buff
      // get the lodestone
      set_property("choiceAdventure1498", "1"); 
      cli_execute("use closed-circuit pay phone");

      // get the buff
      set_property("choiceAdventure1500", "2"); 
      adv1($location[Shadow Rift (The Nearby Plains)], -1, '');
      cli_execute("familiar cookbookbat");
      return true;
    } else {
      // did not win, so we skip and restore hp
      cli_execute("skill tongue of the walrus"); // remove beaten up
      ensureSafeAdv(); // restore hp
      cli_execute("familiar cookbookbat");
      return false;
    }
  } 
  cli_execute("familiar cookbookbat");
  return false;
}

// we can use this instead of count < 55
// boolean canMakeDishes() {
//   if (have($item[Roasted vegetable of Jarlsberg], 6)) {
//     if (have($item[St. Sneaky Pete\'s Whey], 6)) {
//       if (have($item[Yeast of Boris], 3)) {
//         return true;
//       }
//     }
//   }
//   return false;
// }


